package org.rvk.vms.utils.search;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Voluteers search utilities.
 *
 * @author Ashish Kumar Sinha <aksinha.mail@gmail.com>
 */
@Service("volunteersSearchUtils")
@Scope((BeanDefinition.SCOPE_SINGLETON))
public class VolunteersSearchUtils {

    /**
     * to interpret various tokens in a given search key.
     *
     * @param key - the input search key
     * @return - Search tokens mapped on interpreted field type.
     */
    public Map<VolunteersSearchFields, String> interpretWisely(String key){
        if(key == null || key.isEmpty()){
            return null;
        }

        String [] keyArray = key.split("\\s+");
        System.out.println("keyArray = " + keyArray);
        Map<VolunteersSearchFields, String> mappedSearchFields = new HashMap<>(keyArray.length);

        for (String thisKey : keyArray) {
            thisKey = cleanSearchKey(thisKey);
            if(thisKey == null || thisKey.isEmpty()){
                continue;
            }
            VolunteersSearchFields volunteersSearchFields = interpret(thisKey);
            if(volunteersSearchFields != null && !mappedSearchFields.containsKey(volunteersSearchFields)) {
                mappedSearchFields.put(volunteersSearchFields, thisKey.trim());
            }
        }
        System.out.println("### mappedSearchFields.size() = " + mappedSearchFields.size());
        return mappedSearchFields;
    }

    /**
     * to build the JPA search queries. It is array of two strings.
     * First string is the query for fetching records.
     * Second string is the query for fetching count.
     *
     * @param mappedSearchKey
     * @return
     */
    public String[] buildJpaSearchQuery(Map<VolunteersSearchFields, String> mappedSearchKey, int pageSize, int whichPage){

        String resultQueryPrefix = "SELECT V ";
        String  countQueryPrefix = "SELECT count(*) ";
        String whereClause = buildWhereClauseForSearch(mappedSearchKey);
        String paginatedResultQuery = paginationQuery(resultQueryPrefix + whereClause, pageSize, whichPage);

        String []queries = new String [2];
        queries[0] = paginatedResultQuery ;
        queries[1] = countQueryPrefix + whereClause ;

        System.out.println("Volunteers JPA Query for record:: " + queries[0]);
        System.out.println("Volunteers JPA Query for  count:: " + queries[1]);

        return queries;
    }

    private String buildWhereClauseForSearch(Map<VolunteersSearchFields, String> mappedSearchKey){
        StringBuilder queryBuilder = new StringBuilder(" FROM Volunteer v ");
        if(mappedSearchKey != null && !mappedSearchKey.isEmpty()){
            Set<VolunteersSearchFields> keySet = mappedSearchKey.keySet();
            if(keySet != null && !keySet.isEmpty()) {
                boolean first = true;
                for (VolunteersSearchFields thisField : keySet) {
                    if(thisField != null){
                        if(first){
                            queryBuilder.append(" WHERE v." + thisField.whereClause(mappedSearchKey.get(thisField)));
                        } else {
                            queryBuilder.append(" OR v." + thisField.whereClause(mappedSearchKey.get(thisField)));
                        }
                    }
                }
            }
        }
        return queryBuilder.toString();
    }

    private VolunteersSearchFields interpret(String key){
        return VolunteersSearchFields.NAME;
    }

    private String cleanSearchKey(String theKey){
        System.out.println("Splitted thisKey = " + theKey);
        if(theKey == null || theKey.trim().isEmpty()){
            return null;
        }
        theKey = theKey.trim();
        if(theKey.startsWith("\"")) {
            theKey = theKey.substring(1);
        }
        if(theKey.endsWith("\"")) {
            theKey.substring(0, theKey.length()-1);
        }
        System.out.println("Trimmed and Cleaned thisKey = " + theKey);
        return theKey;
    }

    private String paginationQuery(String jpaQuery, int pageSize, int page) {
        if(jpaQuery == null || jpaQuery.isEmpty()) { return jpaQuery; }

        if(pageSize > 0){
            jpaQuery = jpaQuery + " LIMIT " + pageSize;
        } else {
            jpaQuery = jpaQuery + " LIMIT 50 ";
        }

        if(page >= 1) {
            jpaQuery = jpaQuery + "OFFSET " + ((page - 1) * (pageSize > 0 ? pageSize : 50 ));
        }
        System.out.println("Paginated jpaQuery = " + jpaQuery);
        return jpaQuery ;
    }
}

